﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.IO;
using System.Text.RegularExpressions;

namespace WowTourGuideTranslator
{
    /// <summary>
    /// translator class for one tour guide file
    /// </summary>
    class TourGuideTranslator
    {
        #region fields
        
        /// <summary>
        /// path of guide
        /// </summary>
        private string guidePath;

        /// <summary>
        /// langunage to translate to
        /// </summary>
        private string language;

        #endregion fields

        #region constructor

        /// <summary>
        /// Initializes a new instance of the <see cref="TourGuideTranslator"/> class.
        /// </summary>
        /// <param name="guidePath">The guide path.</param>
        /// <param name="lang">The language.</param>
        public TourGuideTranslator(string guidePath, string lang)
        {
            this.guidePath = guidePath;
            this.language = lang;
        }

        #endregion constructor

        #region methods

        /// <summary>
        /// Translates this guide.
        /// </summary>
        public void TranslateGuide()
        {
            StringBuilder guideBuilder = new StringBuilder();

            // load file content
            TextReader guideReader = new StreamReader(this.guidePath);

            string guideText = guideReader.ReadToEnd();

            guideReader.Close();

            // get tourguide content and name
            string startRegex = @"TourGuide:RegisterGuide\(\s*""(?<name>[^""]+)""\s*,\s*(?:nil|""(?<next>[^""]+)"")\s*,\s*""(?<faction>[^""]+)""\s*,\s*function\(\s*\)\s*return\s*\[\[\s*(?<guide>(?:.+[\r\n]*)*)\s*\]\]\s*end\s*\)";
            Regex regexFindStart = new Regex(startRegex, RegexOptions.Multiline);

            Match startMatch = regexFindStart.Match(guideText);

            if (!startMatch.Success)
            {
                DataProvider.Error(@"Could not parse guide in file ""{0}"" check if it is a TourGuide guide!", this.guidePath);
                return;
            }

            // name
            Group nameGroup = startMatch.Groups["name"];
            string name = nameGroup.Value;
            string translatedName = this.TranslateGuideName(name);

            DataProvider.Trace(@"Found guide ""{0}""", name);

            // next guide
            Group nextGroup = startMatch.Groups["next"];
            string translatedNext = nextGroup.Success ? this.TranslateGuideName(nextGroup.Value) : @"nil";

            // faction
            Group factionGroup = startMatch.Groups["faction"];
            string faction = factionGroup.Value;

            //
            // create guide header
            //

            guideBuilder.AppendFormat("TourGuide:RegisterGuide(\"{0}\", \"{1}\", ", translatedName, translatedNext);
            guideBuilder.AppendFormat("\"{0}\", function()\n", faction);
            guideBuilder.Append("return [[\n");

            //
            // handling guide content
            //
            Group conGroup = startMatch.Groups["guide"];

            string[] lines = conGroup.Value.Split('\n');
            int lineCnt = 0;

            // for all lines
            foreach (string line in lines)
            {
                string actionLine = line.Trim();

                if (string.IsNullOrEmpty(actionLine))
                {
                    guideBuilder.AppendLine();
                    continue;
                }

                // report progress
                DataProvider.ReportProgress((++lineCnt * 100) / lines.Length,
                    string.Format(@"Parsing line no {0}/{1} ""{2}"".", lineCnt, lines.Length, line.Trim()));

                if (DataProvider.CancellationPending)
                    throw new TourGuideCancelationException();

                // get action infos
                GuideAction action = new GuideAction(actionLine);
                GuideAction translatedAction = null;

                // Übersetzungen für einzelne Infos generieren
                switch (action.Type)
                {
                    case ActionType.ACCEPT:
                    case ActionType.COMPLETE:
                    case ActionType.TURNIN:
                        translatedAction = this.TranslateQuestAction(action);
                        break;
                    case ActionType.KILL:
                        translatedAction = this.TranslateKillAction(action);
                        break;
                    case ActionType.RUN:
                    case ActionType.FLY:
                    case ActionType.HEARTH:
                    case ActionType.SETHEARTH:
                    case ActionType.GETFLIGHTPOINT:
                    case ActionType.BOAT:
                        translatedAction = this.TranslateLocationAction(action);
                        break;
                    case ActionType.NOTE:
                        translatedAction = this.TranslateNoteAction(action);
                        break;
                    case ActionType.BUY:
                    case ActionType.USE:
                        translatedAction = this.TranslateItemAction(action);
                        break;
                }

                // if we translated successfully append translation
                if (translatedAction != null)
                {
                    guideBuilder.AppendLine(translatedAction.ToString());
                    // report progress
                    DataProvider.Trace("Translated line no {0}/{1} to \"{2}\".\n", lineCnt, lines.Length, translatedAction);
                }
                // otherwise use the old one
                else
                {
                    guideBuilder.AppendLine(actionLine);
                    // report progress
                    DataProvider.Warn("Translation of line no {0}/{1} failed).\n", lineCnt, lines.Length);
                }

            }

            // try to replace all collected text in full text?!


            // append lua string end
            guideBuilder.Append("]]\n");
            guideBuilder.Append("end)");

            // create new file path
            string dirName = Path.Combine(Path.GetDirectoryName(this.guidePath), DataProvider.DataLanguage);
            if (!Directory.Exists(dirName))
            {
                Directory.CreateDirectory(dirName);
            }
            string fileName = Path.Combine(dirName, Path.GetFileNameWithoutExtension(this.guidePath));
            fileName = string.Format(@"{0}_{1}{2}", fileName, this.language, Path.GetExtension(this.guidePath));

            TextWriter fileWriter = File.CreateText(fileName);
            fileWriter.Write(guideBuilder.ToString());
            fileWriter.Close();
            DataProvider.ReportProgress(100);
        }

        /// <summary>
        /// Translates the name of a guide.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <returns></returns>
        private string TranslateGuideName(string name)
        {
            // TODO Extract location name and translate it
            return name + @"_" + this.language;
        }

        /// <summary>
        /// Translates the item action.
        /// </summary>
        /// <param name="action">The action.</param>
        /// <returns></returns>
        private GuideAction TranslateItemAction(GuideAction action)
        {
            GuideAction returnValue = action;
            int itemId = -1;
            WowheadItemParser itemParser = null;

            try
            {
                // if questid exists -> translate
                if (action.SimpleTags.ContainsKey(TagType.Use))
                {
                    itemId = Convert.ToInt32(action.SimpleTags[TagType.Use]);
                }
                else if (action.Id.HasValue && action.Id != 0)
                {
                    itemId = action.Id.Value;
                }

                if (itemId > 0)
                {
                    // try to get buffered wowhead data
                    if (!DataProvider.ItemDict.TryGetValue(itemId, out itemParser))
                    {
                        // or get directly from web
                        itemParser = WowheadItemParser.Parse(itemId, this.language);
                    }

                    returnValue = new GuideAction(action.Type, itemParser.Name.Translated);
                }
                // without itemid try to translate it from the data you have and try to translate the rest
                else
                {
                    returnValue = new GuideAction(action.Type, DataProvider.TryTranslateFromDict(action.Text));
                }

                // process simple tags
                foreach (string tagType in action.SimpleTags.Keys)
                {
                    StringBuilder textBuilder = null;
                    switch (tagType)
                    {
                        // no data
                        case TagType.Optional:
                        case TagType.Town:
                            returnValue.SimpleTags.Add(tagType, string.Empty);
                            break;
                        // simple fully translatable  text data
                        case TagType.Zone:
                        case TagType.Prerequsite:
                        case TagType.Class:
                        case TagType.Race:
                            // try to translate
                            returnValue.SimpleTags.Add(tagType, DataProvider.TryTranslateFromDict(action.SimpleTags[tagType]));
                            break;
                        // free text data (search and replace known texts)
                        case TagType.Note:
                            textBuilder = new StringBuilder(action.SimpleTags[tagType]);
                            // try to replace item text in note
                            if (itemParser != null)
                            {
                                textBuilder.Replace(action.Text, returnValue.Text);

                                // try to translate dropping creature names
                                foreach (WowheadBaseParser.TranslatedWowheadData drop in itemParser.Drops.Values)
                                {
                                    textBuilder.Replace(drop.Name.Original, drop.Name.Translated);
                                }
                            }
                            // try to replace item text in note
                            if (textBuilder.ToString().Contains(action.Text))
                            {
                                textBuilder.Replace(action.Text, returnValue.Text);
                                // try to 
                                if (DataProvider.TranslateNotes)
                                {
                                    returnValue.SimpleTags.Add(tagType, DataProvider.TryTranslateFromDict(textBuilder.ToString()));
                                }
                                else
                                {
                                    returnValue.SimpleTags.Add(tagType, textBuilder.ToString());
                                }
                            }
                            // try to translate Note
                            else if (DataProvider.TranslateNotes)
                            {
                                returnValue.SimpleTags.Add(tagType, DataProvider.TryTranslateFromDict(textBuilder.ToString()));
                            }
                            else
                                returnValue.SimpleTags.Add(tagType, textBuilder.ToString());
                            break;
                        // unknown or untranslatable tag data
                        case TagType.QuestId:
                        case TagType.Use:
                        default:
                            returnValue.SimpleTags.Add(tagType, action.SimpleTags[tagType]);
                            break;
                    }
                }

                // quest objectives
                foreach (GuideAction.QuestObjective quObj in action.QuestObjectives)
                {
                    GuideAction.QuestObjective newQuObj = new GuideAction.QuestObjective()
                    {
                        Quest = DataProvider.TryTranslateFromDict(quObj.Quest),
                        Objective = DataProvider.TryTranslateFromDict(quObj.Objective)
                    };
                    returnValue.QuestObjectives.Add(newQuObj);
                }

                // clone loots
                foreach (GuideAction.Loot loot in action.LootList)
                {
                    returnValue.LootList.Add(loot.Clone());
                }

            }
            catch (Exception ex)
            {
                // report error
                DataProvider.Error(@"Action translation failed with error: {0}", ex);
                // for security set action to the original one
                returnValue = action;
            }

            return returnValue;
        }

        /// <summary>
        /// Translates the note action.
        /// </summary>
        /// <param name="action">The action.</param>
        /// <returns></returns>
        private GuideAction TranslateNoteAction(GuideAction action)
        {
            GuideAction returnValue = action;
            int itemId = -1;
            WowheadItemParser itemParser = null;

            try
            {
                // if questid exists -> translate
                if (action.SimpleTags.ContainsKey(TagType.Use))
                {
                    itemId = Convert.ToInt32(action.SimpleTags[TagType.Use]);
                }
                else if (action.SimpleTags.ContainsKey(TagType.Loot))
                {
                    itemId = Convert.ToInt32(action.SimpleTags[TagType.Loot]);
                }

                if (itemId > 0)
                {
                    // try to get buffered wowhead data
                    if (!DataProvider.ItemDict.TryGetValue(itemId, out itemParser))
                    {
                        // or get directly from web
                        itemParser = WowheadItemParser.Parse(itemId, this.language);
                    }

                    // Try partial translation
                    if (action.Text.Contains(itemParser.Name.Original))
                    {
                        // if note translation is active translate partial first, 
                        // then try full translation
                        // (this makes translation of Notes with item texts easier)
                        if (DataProvider.TranslateNotes && action.Text.Length > itemParser.Name.Original.Length)
                        {
                            returnValue = new GuideAction(action.Type, action.Text.Replace(itemParser.Name.Original, itemParser.Name.Translated));
                        }
                        else
                        {
                            // translate the item name because item name is in the note and they have the same length
                            returnValue = new GuideAction(action.Type, DataProvider.TryTranslateFromDict(action.Text));
                        }
                    }
                    // translate full note
                    else if (DataProvider.TranslateNotes)
                    {
                        returnValue = new GuideAction(action.Type, DataProvider.TryTranslateFromDict(action.Text));
                    }
                    else
                    {
                        returnValue = new GuideAction(action.Type, action.Text);
                    }
                }
                // without itemid leave the name and try to translate the rest
                else
                {
                    // or try to translate if selected
                    if (DataProvider.TranslateNotes)
                    {
                        returnValue = new GuideAction(action.Type, DataProvider.TryTranslateFromDict(action.Text));
                    }
                    else
                    {
                        returnValue = new GuideAction(action.Type, action.Text);
                    }
                }

                // process simple tags
                foreach (string tagType in action.SimpleTags.Keys)
                {
                    switch (tagType)
                    {
                        // no data
                        case TagType.Optional:
                        case TagType.Town:
                            returnValue.SimpleTags.Add(tagType, string.Empty);
                            break;
                        // simple fully translatable  text data
                        case TagType.Zone:
                        case TagType.Prerequsite:
                        case TagType.Class:
                        case TagType.Race:
                            // try to translate
                            returnValue.SimpleTags.Add(tagType, DataProvider.TryTranslateFromDict(action.SimpleTags[tagType]));
                            break;
                        // free text data (search and replace known texts)
                        case TagType.Note:
                            // try to replace item text in note
                            if (itemParser != null)
                            {
                                StringBuilder textBuilder = new StringBuilder(action.SimpleTags[tagType]);
                                textBuilder.Replace(action.Text, returnValue.Text);

                                // try to translate dropping creature names
                                foreach (WowheadBaseParser.TranslatedWowheadData drop in itemParser.Drops.Values)
                                {
                                    textBuilder.Replace(drop.Name.Original, drop.Name.Translated);
                                }

                                // translate notes or not
                                if (DataProvider.TranslateNotes)
                                {
                                    returnValue.SimpleTags.Add(tagType, DataProvider.TryTranslateFromDict(textBuilder.ToString()));
                                }
                                else
                                    returnValue.SimpleTags.Add(tagType, textBuilder.ToString());
                            }
                            else if (DataProvider.TranslateNotes)
                                returnValue.SimpleTags.Add(tagType, DataProvider.TryTranslateFromDict(action.SimpleTags[tagType].Replace(action.Text, returnValue.Text)));
                            else
                                returnValue.SimpleTags.Add(tagType, action.SimpleTags[tagType].Replace(action.Text, returnValue.Text));
                            break;
                        // unknown or untranslatable tag data
                        case TagType.QuestId:
                        case TagType.Use:
                        default:
                            returnValue.SimpleTags.Add(tagType, action.SimpleTags[tagType]);
                            break;
                    }
                }

                // quest objectives
                foreach (GuideAction.QuestObjective quObj in action.QuestObjectives)
                {
                    GuideAction.QuestObjective newQuObj = new GuideAction.QuestObjective()
                    {
                        Quest = DataProvider.TryTranslateFromDict(quObj.Quest),
                        Objective = DataProvider.TryTranslateFromDict(quObj.Objective)
                    };
                    returnValue.QuestObjectives.Add(newQuObj);
                }

                // clone loots
                foreach (GuideAction.Loot loot in action.LootList)
                {
                    returnValue.LootList.Add(loot.Clone());
                }

            }
            catch (Exception ex)
            {
                // report error
                DataProvider.Error(@"Action translation failed with error: {0}", ex);
                // for security set action to the original one
                returnValue = action;
            }

            return returnValue;
        }

        /// <summary>
        /// Translates the location action.
        /// </summary>
        /// <param name="action">The action.</param>
        /// <returns></returns>
        private GuideAction TranslateLocationAction(GuideAction action)
        {
            // try to translate location
            GuideAction returnValue = new GuideAction(action.Type, DataProvider.TryTranslateFromDict(action.Text));

            try
            {
                // process simple tags
                foreach (string tagType in action.SimpleTags.Keys)
                {
                    StringBuilder textBuilder = null;
                    switch (tagType)
                    {
                        // no data
                        case TagType.Optional:
                        case TagType.Town:
                            returnValue.SimpleTags.Add(tagType, string.Empty);
                            break;
                        // simple fully translatable  text data
                        case TagType.Zone:
                        case TagType.Prerequsite:
                        case TagType.Class:
                        case TagType.Race:
                            // try to translate
                            returnValue.SimpleTags.Add(tagType, DataProvider.TryTranslateFromDict(action.SimpleTags[tagType]));
                            break;
                        // free text data (search and replace known texts)
                        case TagType.Note:
                            textBuilder = new StringBuilder(action.SimpleTags[tagType]);
                            // try to replace location text in note
                            if (action.SimpleTags[tagType].Contains(action.Text))
                            {
                                textBuilder.Replace(action.Text, returnValue.Text);
                                if (DataProvider.TranslateNotes)
                                {
                                    returnValue.SimpleTags.Add(tagType, DataProvider.TryTranslateFromDict(textBuilder.ToString()));
                                }
                                else
                                {
                                    returnValue.SimpleTags.Add(tagType, textBuilder.ToString());
                                }
                            }
                            // try to translate Note
                            else if (DataProvider.TranslateNotes)
                            {
                                returnValue.SimpleTags.Add(tagType, DataProvider.TryTranslateFromDict(action.SimpleTags[tagType]));
                            }
                            else
                                returnValue.SimpleTags.Add(tagType, action.SimpleTags[tagType]);
                            break;
                        // unknown or untranslatable tag data
                        case TagType.QuestId:
                        case TagType.Use:
                        default:
                            returnValue.SimpleTags.Add(tagType, action.SimpleTags[tagType]);
                            break;
                    }
                }

                // quest objectives
                foreach (GuideAction.QuestObjective quObj in action.QuestObjectives)
                {
                    GuideAction.QuestObjective newQuObj = new GuideAction.QuestObjective()
                    {
                        Quest = DataProvider.TryTranslateFromDict(quObj.Quest),
                        Objective = DataProvider.TryTranslateFromDict(quObj.Objective)
                    };
                    returnValue.QuestObjectives.Add(newQuObj);
                }

                // clone loots
                foreach (GuideAction.Loot loot in action.LootList)
                {
                    returnValue.LootList.Add(loot.Clone());
                }

            }
            catch (Exception ex)
            {
                // report error
                DataProvider.Error(@"Action translation failed with error: {0}", ex);
                // for security set action to the original one
                returnValue = action;
            }

            return returnValue;
        }

        /// <summary>
        /// Translates the kill action.
        /// </summary>
        /// <param name="action">The action.</param>
        /// <returns></returns>
        private GuideAction TranslateKillAction(GuideAction action)
        {
            GuideAction returnValue = action;
            int lootId = -1;
            WowheadItemParser itemParser = null;

            try
            {
                // if questid exists -> translate
                if (action.SimpleTags.ContainsKey(TagType.Loot))
                {
                    lootId = Convert.ToInt32(action.SimpleTags[TagType.QuestId]);

                    // get data from wowhead 
                    if (!DataProvider.ItemDict.TryGetValue(lootId, out itemParser))
                    {
                        itemParser = WowheadItemParser.Parse(lootId, this.language);
                    }

                    // create new translated action
                    returnValue = new GuideAction(action.Type, itemParser.Name.Translated);
                }
                // without questid leave the name and try to translate the rest
                else
                {
                    returnValue = new GuideAction(action.Type, DataProvider.TryTranslateFromDict(action.Text));
                }

                // process simple tags
                foreach (string tagType in action.SimpleTags.Keys)
                {
                    switch (tagType)
                    {
                        // no data
                        case TagType.Optional:
                        case TagType.Town:
                            returnValue.SimpleTags.Add(tagType, string.Empty);
                            break;
                        // simple fully translatable  text data
                        case TagType.Zone:
                        case TagType.Prerequsite:
                        case TagType.Class:
                        case TagType.Race:
                            // try to translate
                            returnValue.SimpleTags.Add(tagType, DataProvider.TryTranslateFromDict(action.SimpleTags[tagType]));
                            break;
                        // free text data (search and replace known texts)
                        case TagType.Note:
                            // try to replace text from questParser
                            if (itemParser != null)
                            {
                                StringBuilder noteBuilder = new StringBuilder(action.SimpleTags[tagType]);

                                // try to replace quest name
                                noteBuilder.Replace(itemParser.Name.Original, itemParser.Name.Original);

                                // try to replace all NPC names
                                foreach (WowheadBaseParser.TranslatedWowheadData data in itemParser.Drops.Values)
                                {
                                    noteBuilder.Replace(data.Name.Original, data.Name.Translated);
                                }

                                // if translate notes is checked try to translate the resulting note
                                if (DataProvider.TranslateNotes)
                                {
                                    returnValue.SimpleTags.Add(tagType, DataProvider.TryTranslateFromDict(noteBuilder.ToString()));
                                }
                                else
                                    returnValue.SimpleTags.Add(tagType, noteBuilder.ToString());
                            }
                            else if (DataProvider.TranslateNotes)
                            {
                                returnValue.SimpleTags.Add(tagType, DataProvider.TryTranslateFromDict(action.SimpleTags[tagType]));
                            }
                            else
                                returnValue.SimpleTags.Add(tagType, action.SimpleTags[tagType]);
                            break;
                        // unknown or untranslatable tag data
                        case TagType.QuestId:
                        case TagType.Use:
                        default:
                            returnValue.SimpleTags.Add(tagType, action.SimpleTags[tagType]);
                            break;
                    }
                }

                // quest objectives
                foreach (GuideAction.QuestObjective quObj in action.QuestObjectives)
                {
                    GuideAction.QuestObjective newQuObj = new GuideAction.QuestObjective()
                    {
                        Quest = DataProvider.TryTranslateFromDict(quObj.Quest),
                        Objective = DataProvider.TryTranslateFromDict(quObj.Objective)
                    };
                    returnValue.QuestObjectives.Add(newQuObj);
                }

                // clone loots
                foreach (GuideAction.Loot loot in action.LootList)
                {
                    returnValue.LootList.Add(loot.Clone());
                }

            }
            catch (Exception ex)
            {
                // report error
                DataProvider.Error(@"Action translation failed with error: {0}", ex);
                // for security set action to the original one
                returnValue = action;
            }

            return returnValue;
        }

        /// <summary>
        /// Translates the quest action.
        /// </summary>
        /// <param name="action">The action.</param>
        /// <returns></returns>
        private GuideAction TranslateQuestAction(GuideAction action)
        {
            int partNo = -1;
            GuideAction returnValue = action;
            int questId = -1;
            bool isFollowUp = false;
            WowheadQuestParser questParser = null;

            try
            {
                // get quest part no
                Match partNoMatch = Regex.Match(action.Text, @"[^(]+\s*\(Part\s*(?<number>\d+)\)", RegexOptions.IgnoreCase);
                if (partNoMatch.Success)
                {
                    partNo = Convert.ToInt32(partNoMatch.Groups[@"number"].Value);
                }

                // test if follow up
                Match followUpMatch = Regex.Match(action.Text, @"[^(]+\s*\(follow[- ]up\)", RegexOptions.IgnoreCase);
                if (followUpMatch.Success)
                {
                    isFollowUp = true;
                }

                // if questid exists -> translate
                if (action.SimpleTags.ContainsKey(TagType.QuestId))
                {
                    questId = Convert.ToInt32(action.SimpleTags[TagType.QuestId]);

                    // get data from wowhead 

                    if (!DataProvider.QuestDict.TryGetValue(questId, out questParser))
                    {
                        questParser = WowheadQuestParser.Parse(questId, this.language);
                    }
                    

                    // create new translated action
                    StringBuilder translatedNameBuilder = new StringBuilder(questParser.Name.Translated);
                    if (partNo > 0)
                    {
                        // TODO Teil sprachunabhängig machen
                        //translatedNameBuilder.AppendFormat(@" (Teil {0})", partNo);
                        translatedNameBuilder.AppendFormat(DataProvider.TryTranslateFromDict(@" (part {0})"), partNo);
                    }
                    else if (isFollowUp)
                    {
                        translatedNameBuilder.Append(@" (follow-up)");
                    }

                    returnValue = new GuideAction(action.Type, translatedNameBuilder.ToString());
                }
                // without questid leave the name and try to translate the rest
                else
                {
                    returnValue = new GuideAction(action.Type, DataProvider.TryTranslateFromDict(action.Text));
                }

                // process simple tags
                foreach (string tagType in action.SimpleTags.Keys)
                {
                    switch (tagType)
                    {
                        // no data
                        case TagType.Optional:
                        case TagType.Town:
                            returnValue.SimpleTags.Add(tagType, string.Empty);
                            break;
                        // simple fully translatable  text data
                        case TagType.Zone:
                        case TagType.Prerequsite:
                        case TagType.Class:
                        case TagType.Race:
                            // try to translate
                            returnValue.SimpleTags.Add(tagType, DataProvider.TryTranslateFromDict(action.SimpleTags[tagType]));
                            break;
                        // free text data (search and replace known texts)
                        case TagType.Note:
                            // try to replace text from questParser
                            if (questParser != null)
                            {
                                StringBuilder noteBuilder = new StringBuilder(action.SimpleTags[tagType]);

                                // try to replace quest name
                                noteBuilder.Replace(questParser.Name.Original, questParser.Name.Original);

                                // try to replace all item names
                                foreach (WowheadQuestParser.Objective obj in questParser.Items.Values)
                                {
                                    noteBuilder.Replace(obj.Name.Original, obj.Name.Translated);
                                }

                                // try to replace all NPC names
                                foreach (WowheadQuestParser.Objective obj in questParser.Kills.Values)
                                {
                                    noteBuilder.Replace(obj.Name.Original, obj.Name.Translated);
                                }
                                // if translate notes is checked try to translate the resulting note
                                if (DataProvider.TranslateNotes)
                                {
                                    returnValue.SimpleTags.Add(tagType, DataProvider.TryTranslateFromDict(noteBuilder.ToString()));
                                }
                                else
                                    returnValue.SimpleTags.Add(tagType, noteBuilder.ToString());
                            }
                            else if (DataProvider.TranslateNotes)
                            {
                                returnValue.SimpleTags.Add(tagType, DataProvider.TryTranslateFromDict(action.SimpleTags[tagType]));
                            }
                            else
                                returnValue.SimpleTags.Add(tagType, action.SimpleTags[tagType]);
                            break;
                        // unknown or untranslatable tag data
                        case TagType.QuestId:
                        case TagType.Use:
                        default:
                            returnValue.SimpleTags.Add(tagType, action.SimpleTags[tagType]);
                            break;
                    }
                }

                // quest objectives
                foreach (GuideAction.QuestObjective quObj in action.QuestObjectives)
                {
                    GuideAction.QuestObjective newQuObj = new GuideAction.QuestObjective()
                    {
                        Quest = DataProvider.TryTranslateFromDict(quObj.Quest),
                        Objective  = DataProvider.TryTranslateFromDict(quObj.Objective)
                    };
                    returnValue.QuestObjectives.Add(newQuObj);
                }

                // clone loots
                foreach (GuideAction.Loot loot in action.LootList)
                {
                    returnValue.LootList.Add(loot.Clone());
                }

            }
            catch (Exception ex)
            {
                // report error
                DataProvider.Error(@"Action translation failed with error: {0}", ex);
                // for security set action to the original one
                returnValue = action;
            }

            return returnValue;
        }

        /// <summary>
        /// Handles the translation of the note text.
        /// </summary>
        /// <param name="noteText">The note text.</param>
        /// <param name="translations">The translations to use for the note translation.
        /// Items must be of type <seealso cref="TranslatedPair"/> or of a type that can be 
        /// casted to an enumeration of <seealso cref="TranslatedPair"/> </param>
        /// <returns></returns>
        private string HandleNoteText(string noteText, params object[] translations)
        {
            StringBuilder builder = new StringBuilder(noteText);

            foreach (object param in translations)
            {
                if (param is TranslatedPair)
                {
                    TranslatedPair pair = (TranslatedPair)param;
                    builder.Replace(pair.Original, pair.Translated);
                }
                else if (param is IEnumerable<TranslatedPair>)
                {
                    foreach (TranslatedPair pair in (IEnumerable<TranslatedPair>)param)
                    {
                        builder.Replace(pair.Original, pair.Translated);
                    }
                }
            }

            // if translate notes is checked try to translate the resulting note
            if (DataProvider.TranslateNotes)
            {
                string buildedNote = builder.ToString();
                if (DataProvider.HasTranslation(buildedNote))
                {
                    return DataProvider.TryTranslateFromDict(buildedNote);
                }
            }

            return builder.ToString();
        }

        #endregion methods
    }
}
